/**
 * Copyright 2007 Igor Chaves Cananéa
 *
 * This file is part of PBSFW
 *
 * PBSFW is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * PBSFW is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <iostream>
#include <cstdio>
#include "trace.h"
#include "defines.h"
#include "simulatorinterface.h"
using namespace std;
using namespace pbsfw;

namespace util {
    DebugLevel Trace::currentLevel = PARANOID;
    bool Trace::active = false;
    unsigned Trace::count = 0;
    ostream &Trace::out = cerr;
    bool Trace::indentation = false;
    unsigned Trace::indentLen = 3;

    const char *Trace::time() const {
        static char t[256];
        sprintf(t, "%.6lf", simulator.now());
        return t;
    }

    Trace::Trace(DebugLevel debugLevel, const char *className,
                const char *methodName)
        : debugLevel(debugLevel), className(className),methodName(methodName){
        if (this->isActive()) {
            if (className == 0) {
                this->className = "";
            }
            ++count;

            if( this->currentLevel == PARANOID ){
                Trace::out << this->indent() << "[" << this->className << "."
                    << this->methodName << "]@" << this->time() << ": Trace started.\n";
            }
        }
    }

    Trace::Trace(const char *className, const char *methodName)
        : debugLevel(INFORMATION), className(className), methodName(methodName) {
        if (this->isActive()) {
            if (className == 0) {
                this->className = "";
            }
            ++count;

            if( this->currentLevel == PARANOID ){
                Trace::out << this->indent() << "[" << this->className << "."
                    << this->methodName << "]@" << this->time() << ": Trace started.\n";
            }
        }
    }

    Trace::~Trace() {
        if (this->isActive() ) {
            if (this->currentLevel == PARANOID ) {
                Trace::out << this->indent() << "[" << this->className << "."
                        << this->methodName << "]@" << this->time() << ": Trace ended.\n";
            }
            --count;
        }
    }

    void Trace::do_debug(const char *msg) const {
        Trace::out << this->indent() << "[" << this->className << "."
                    << this->methodName << "]@" << this->time() << ": " << msg << "\n";
    }

    void Trace::do_debug(double value, const char *msg) const {
        Trace::out << this->indent() << "[" << this->className << "."
                    << this->methodName << "]@" << this->time() << ": " << msg << " -> "
                    <<value << "\n";
    }

    void Trace::do_debugf(const char *msg, va_list ap) const {
        static char buffer[2048];

        vsnprintf(buffer, 2047, msg, ap);
        Trace::out << this->indent() << "[" << this->className << "."
                    << this->methodName << "]@" << this->time() << ": " << buffer << "\n";
    }

    const char * Trace::indent() const {
        static char buffer[2048];
        if( this->indentation ){
            uint i;
            for( i = 0; i < this->count*this->indentLen && i < 2048-i; i++ ){
                buffer[i] = ' ';
            }
            buffer[i] = '\0';
        } else {
            sprintf( buffer, "%d)", count );
        }
        return buffer;
    }
};
